﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Runtime.InteropServices;

namespace RxjhServer.Network
{
    public class Listener
    {
        private AppState appState = AppState.Stoped;

        private Listener.ShowMsg AddMsgDelegate;

        public TcpServer Server = new TcpServer();

        private bool m_Disposed;

        private void SetServerState()
        {
            this.AddMsgDelegate = new Listener.ShowMsg(this.AddMsg);
            this.Server.OnPrepareListen += new TcpServerEvent.OnPrepareListenEventHandler(this.OnPrepareListen);
            this.Server.OnAccept += new TcpServerEvent.OnAcceptEventHandler(this.OnAccept);
            this.Server.OnSend += new TcpServerEvent.OnSendEventHandler(this.OnSend);
            this.Server.OnReceive += new TcpServerEvent.OnReceiveEventHandler(this.OnReceive);
            this.Server.OnClose += new TcpServerEvent.OnCloseEventHandler(this.OnClose);
            this.Server.OnShutdown += new TcpServerEvent.OnShutdownEventHandler(this.OnShutdown);
            this.SetAppState(AppState.Stoped);
        }

        public Listener(ushort port)
        {
            try
            {
                this.m_Disposed = false;
                this.SetServerState();
                this.Start(port);
            }
            catch (Exception ex)
            {
                this.SetAppState(AppState.Error);
                this.AddMsg(ex.Message, 1);
            }
        }

        ~Listener()
        {
        }

        private void Start(ushort port)
        {
            try
            {
                this.SetAppState(AppState.Starting);
                this.Server.IpAddress = "0.0.0.0";
                this.Server.Port = port;
                if (World.当前线路类型 == 0)
                {
                    this.Server.SendPolicy = SendPolicy.Safe;
                }
                else
                {
                    this.Server.SendPolicy = SendPolicy.Direct;
                }
                if (!this.Server.Start(World.ServerIDStart))
                {
                    this.SetAppState(AppState.Stoped);
                    throw new Exception(string.Format("监听端口失败 -> {0}({1})", this.Server.ErrorMessage, this.Server.ErrorCode));
                }
                World.主Socket = true;
                World.游戏服务器端口2 = (int)port;
                this.AddMsg(string.Format("开始监听端口 {0}:{1}", "0.0.0.0", port), 3);
                World.conn.发送(string.Concat(new object[]
                {
                    "更新服务器端口|",
                    World.服务器ID,
                    "|",
                    port
                }));
                this.SetAppState(AppState.Started);
            }
            catch (Exception ex)
            {
                this.AddMsg(ex.Message, 1);
            }
        }

        public void Stop()
        {
            try
            {
                this.SetAppState(AppState.Stoping);
                World.主Socket = false;
                if (!this.m_Disposed)
                {
                    if (this.Server.Stop())
                    {
                        this.SetAppState(AppState.Stoped);
                        this.m_Disposed = true;
                    }
                    else
                    {
                        this.AddMsg("停止通信服务出错", 1);
                    }
                }
            }
            catch (Exception ex)
            {
                this.AddMsg("停止通信服务出错2 " + ex.Message, 1);
            }
        }

        public void Dispose()
        {
            try
            {
                this.Server.Destroy();
            }
            catch (Exception ex)
            {
                this.AddMsg("终止通信服务出错 " + ex.Message, 1);
            }
        }

        private HandleResult OnShutdown()
        {
            this.AddMsg("停止通信组件服务", 3);
            return HandleResult.Ok;
        }

        private void Disconnect(IntPtr connId)
        {
            try
            {
                if (!this.Server.Disconnect(connId, true))
                {
                    throw new Exception(string.Format("断开连接({0}) 错误", connId));
                }
                this.AddMsg(string.Format("$({0}) 断开连接", connId), 3);
            }
            catch (Exception ex)
            {
                this.AddMsg(ex.Message, 1);
            }
        }

        private HandleResult OnPrepareListen(IntPtr soListen)
        {
            return HandleResult.Ok;
        }

        private ClientInfo SetClientData(IntPtr connId, string ip, ushort port)
        {
            try
            {
                return new ClientInfo
                {
                    ConnId = connId,
                    IpAddress = ip,
                    Port = port,
                    Server = this.Server,
                    WorldId = this.addWorldIdd()
                };
            }
            catch
            {
            }
            return null;
        }

        private int addWorldIdd()
        {
            for (int i = 300; i < 65500; i++)
            {
                if (!World.list.ContainsKey(i))
                {
                    return i;
                }
            }
            return 0;
        }

        private static long IpToInt(string ip)
        {
            char[] separator = new char[]
            {
                '.'
            };
            string[] array = ip.Split(separator);
            return long.Parse(array[0]) << 24 | long.Parse(array[1]) << 16 | long.Parse(array[2]) << 8 | long.Parse(array[3]);
        }

        private HandleResult OnAccept(IntPtr connId, IntPtr pClient)
        {
            string empty = string.Empty;
            ushort port = 0;
            try
            {
                if (this.Server.GetRemoteAddress(connId, ref empty, ref port))
                {
                    if (World.线程同步变量)
                    {
                        return HandleResult.Ok;
                    }
                    if (World.封IP)
                    {
                        long num = Listener.IpToInt(empty);
                        uint num2 = (uint)IPAddress.HostToNetworkOrder((int)num);
                        IPAddress iPAddress = new IPAddress((long)((ulong)num2));
                        if (World.BipList.Contains(iPAddress))
                        {
                            if (World.断开连接)
                            {
                                this.Disconnect(connId);
                            }
                            if (World.关闭连接)
                            {
                                this.Stop();
                            }
                        }
                        DateTime value = DateTime.Now;
                        int num3 = 0;
                        foreach (NetState current in World.list.Values)
                        {
                            if (current.ToString() == iPAddress.ToString())
                            {
                                value = current.Ljtime;
                                num3++;
                            }
                        }
                        if (num3 > World.游戏登陆端口最大连接数)
                        {
                            int num4 = (int)DateTime.Now.Subtract(value).TotalMilliseconds;
                            if (num4 >= World.游戏登陆端口最大连接时间数)
                            {
                                goto IL_275;
                            }
                            Form1.WriteLine(1, "到达IP最大连接数" + iPAddress.ToString());
                            if (World.加入过滤列表 && !World.BipList.Contains(iPAddress))
                            {
                                World.BipList.Add(iPAddress);
                            }
                            this.Disconnect(connId);
                            try
                            {
                                Queue queue = Queue.Synchronized(new Queue());
                                using (IEnumerator<NetState> enumerator2 = World.list.Values.GetEnumerator())
                                {
                                    while (enumerator2.MoveNext())
                                    {
                                        NetState current2 = enumerator2.Current;
                                        if (current2.ToString() == iPAddress.ToString())
                                        {
                                            queue.Enqueue(current2);
                                        }
                                    }
                                    goto IL_1BD;
                                }
                                IL_1A8:
                                NetState netState = (NetState)queue.Dequeue();
                                netState.Dispose();
                                IL_1BD:
                                if (queue.Count <= 0)
                                {
                                    goto IL_275;
                                }
                                goto IL_1A8;
                            }
                            catch
                            {
                                goto IL_275;
                            }
                        }
                        ClientInfo clientInfo = this.SetClientData(connId, empty, port);
                        if (this.Server.SetConnectionExtra(connId, clientInfo))
                        {
                            NetState netState2 = new NetState(clientInfo);
                            netState2.Start();
                        }
                        else
                        {
                            this.AddMsg(string.Format(" > [{0},OnAccept] -> SetConnectionExtra(connId, ci) Error", connId), 1);
                        }
                    }
                    else
                    {
                        ClientInfo clientInfo2 = this.SetClientData(connId, empty, port);
                        if (this.Server.SetConnectionExtra(connId, clientInfo2))
                        {
                            NetState netState3 = new NetState(clientInfo2);
                            netState3.Start();
                        }
                        else
                        {
                            this.AddMsg(string.Format(" > [{0},OnAccept] -> SetConnectionExtra(connId, ci) Error", connId), 1);
                        }
                    }
                }
                else
                {
                    this.AddMsg(string.Format(" > [{0},OnAccept] -> GetRemoteAddress(connId, ref ip, ref port) Error", connId), 1);
                }
                IL_275:;
            }
            catch (Exception)
            {
            }
            return HandleResult.Ok;
        }

        private HandleResult OnSend(IntPtr connId, byte[] bytes)
        {
            World.发送速度 += (double)bytes.Length;
            return HandleResult.Ok;
        }

        private HandleResult OnReceive(IntPtr connId, byte[] bytes)
        {
            HandleResult result;
            try
            {
                IntPtr zero = IntPtr.Zero;
                if (this.Server.GetConnectionExtra(connId, ref zero))
                {
                    ClientInfo clientInfo = (ClientInfo)Marshal.PtrToStructure(zero, typeof(ClientInfo));
                    int num = bytes.Length;
                    if (num <= 0)
                    {
                        result = HandleResult.Error;
                        return result;
                    }
                    World.接收速度 += (double)num;
                    using (new Lock(clientInfo.Client.m_Buffer, "this.m_Buffer"))
                    {
                        clientInfo.Client.m_Buffer.Enqueue(bytes, 0, num);
                    }
                    clientInfo.Client.HandleReceive(clientInfo.Client);
                }
                result = HandleResult.Ok;
            }
            catch (Exception)
            {
                result = HandleResult.Error;
            }
            return result;
        }

        private HandleResult OnClose(IntPtr connId, SocketOperation enOperation, int errorCode)
        {
            int num = 0;
            try
            {
                IntPtr zero = IntPtr.Zero;
                if (this.Server.GetConnectionExtra(connId, ref zero))
                {
                    num = 1;
                    ClientInfo clientInfo = (ClientInfo)Marshal.PtrToStructure(zero, typeof(ClientInfo));
                    clientInfo.Client.logout(enOperation, errorCode);
                    num = 2;
                }
                if (errorCode == 0)
                {
                    this.AddMsg(string.Format("[断开 连接ID:{0} ExceStep:{1}]", connId, num), 3);
                }
                else
                {
                    this.AddMsg(string.Format("[断开 连接ID:{0} ExceStep:{1}] -> OP:{2},CODE:{3}", new object[]
                    {
                        connId,
                        num,
                        enOperation,
                        errorCode
                    }), 3);
                }
                num = 3;
                if (!this.Server.SetConnectionExtra(connId, null))
                {
                    num = 4;
                    this.AddMsg(string.Format("[断开错误:SetConnectionExtra({0}, null) fail ExceStep:{1}] -> OP:{2},CODE:{3}", new object[]
                    {
                        connId,
                        num,
                        enOperation,
                        errorCode
                    }), 1);
                }
                num = 5;
            }
            catch (Exception ex)
            {
                this.AddMsg(string.Concat(new object[]
                {
                    "断开错误 连接ID:",
                    connId,
                    " OP:",
                    enOperation,
                    " CODE:",
                    errorCode,
                    " ExceStep:",
                    num,
                    " ExceptionMsg:",
                    ex.Message
                }), 1);
            }
            return HandleResult.Ok;
        }

        private void SetAppState(AppState state)
        {
            this.appState = state;
            World.SocketState = this.appState.ToString();
        }

        private void AddMsg(string msg, int type)
        {
            Form1.WriteLine(type, msg);
        }

        private delegate void ShowMsg(string msg, int type);
    }
}
